<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="format-detection" content="telephone=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="icon" href="https://cdn.qiniu.wenzuo.net/catch6.github.io/avatar.jpg?v=2.3.0" type="image/png" sizes="16x16"><link rel="icon" href="https://cdn.qiniu.wenzuo.net/catch6.github.io/avatar.jpg?v=2.3.0" type="image/png" sizes="32x32"><meta name="baidu-site-verification" content="code-4sfQ80iYvV"><meta name="description" content="Catch 的个人笔记集">
<meta property="og:type" content="website">
<meta property="og:title" content="Catch Notebook">
<meta property="og:url" content="https://catch6.github.io/index.html">
<meta property="og:site_name" content="Catch Notebook">
<meta property="og:description" content="Catch 的个人笔记集">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="Catch">
<meta property="article:tag" content="互联网,编程,程序,分布式,Java">
<meta name="twitter:card" content="summary"><title>Catch Notebook | 学习这件事，不是缺乏时间，而是缺乏努力。</title><link ref="canonical" href="https://catch6.github.io/index.html"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/css/all.min.css" type="text/css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" type="text/css"><link rel="stylesheet" href="/css/index.css?v=2.3.0"><script>var Stun = window.Stun || {};
var CONFIG = {
  root: '/',
  algolia: undefined,
  assistSearch: undefined,
  fontIcon: {"prompt":{"success":"fas fa-check-circle","info":"fas fa-arrow-circle-right","warning":"fas fa-exclamation-circle","error":"fas fa-times-circle"},"copyBtn":"fas fa-copy"},
  sidebar: {"offsetTop":"20px","tocMaxDepth":6},
  header: {"enable":true,"showOnPost":true,"scrollDownIcon":false},
  postWidget: {"endText":true},
  nightMode: {"enable":true},
  back2top: {"enable":true},
  codeblock: {"style":"default","highlight":"light","wordWrap":false},
  reward: false,
  fancybox: true,
  zoomImage: {"gapAside":"20px"},
  galleryWaterfall: undefined,
  lazyload: true,
  pjax: undefined,
  externalLink: {"icon":{"enable":true,"name":"fas fa-external-link-alt"}},
  shortcuts: undefined,
  prompt: {"copyButton":"复制","copySuccess":"复制成功","copyError":"复制失败"},
  sourcePath: {"js":"js","css":"css","images":"images"},
};

window.CONFIG = CONFIG;</script><meta name="generator" content="Hexo 5.2.0"></head><body><div class="container" id="container"><header class="header" id="header"><div class="header-inner"><nav class="header-nav header-nav--fixed"><div class="header-nav-inner"><div class="header-nav-menubtn"><i class="fas fa-bars"></i></div><div class="header-nav-menu"><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/"><span class="header-nav-menu-item__icon"><i class="fas fa-home"></i></span><span class="header-nav-menu-item__text">首页</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/archives/"><span class="header-nav-menu-item__icon"><i class="fas fa-folder-open"></i></span><span class="header-nav-menu-item__text">归档</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/categories/"><span class="header-nav-menu-item__icon"><i class="fas fa-layer-group"></i></span><span class="header-nav-menu-item__text">分类</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/tags/"><span class="header-nav-menu-item__icon"><i class="fas fa-tags"></i></span><span class="header-nav-menu-item__text">标签</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/links/"><span class="header-nav-menu-item__icon"><i class="fas fa-link"></i></span><span class="header-nav-menu-item__text">友链</span></a></div></div><div class="header-nav-search"><span class="header-nav-search__icon"><i class="fas fa-search"></i></span><span class="header-nav-search__text">搜索</span></div><div class="header-nav-mode"><div class="mode"><div class="mode-track"><span class="mode-track-moon"></span><span class="mode-track-sun"></span></div><div class="mode-thumb"></div></div></div></div></nav><div class="header-banner"><div class="header-banner-info"><div class="header-banner-info__title">Catch Notebook</div><div class="header-banner-info__subtitle">学习这件事，不是缺乏时间，而是缺乏努力。</div></div></div></div></header><main class="main" id="main"><div class="main-inner"><div class="content-wrap" id="content-wrap"><div class="content content-home" id="content"><section class="postlist"><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/12/14/mac-use-lrzsz.html">mac 下使用 lrzsz</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-12-14</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h2 id="介绍"   >
          <a href="#介绍" class="heading-link"><i class="fas fa-link"></i></a>介绍</h2>
      <p>在 mac 下，实现与服务器进行便捷的文件上传和下载操作。</p>

        <h2 id="步骤"   >
          <a href="#步骤" class="heading-link"><i class="fas fa-link"></i></a>步骤</h2>
      <ol>
<li><p>安装支持 rz 和 sz 命令的 lrzsz：<code>brew install lrzsz</code></p>
</li>
<li><p>在本地<code>/usr/local/bin/</code>目录下保存<code>iterm2-send-zmodem.sh</code>和<code>iterm2-recv-zmodem.sh</code>两个脚本, 下面有备用</p>
</li>
<li><p>设置一下两个脚本的权限，一般 chmod 777 就行了 <code>chmod 777 /usr/local/bin/iterm2-*</code></p>
</li>
<li><p>设置 Iterm2 的 Tirgger 特性，profiles-&gt;default-&gt;editProfiles-&gt;Advanced 中的 Tirgger</p>
</li>
<li><p>添加两条 trigger，分别设置 Regular expression，Action，Parameters，Instant 如下：</p>
<figure class="highlight plain"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">1.第一条</span><br><span class="line">        Regular expression: rz waiting to receive.\*\*B0100</span><br><span class="line">        Action: Run Silent Coprocess</span><br><span class="line">        Parameters: &#x2F;usr&#x2F;local&#x2F;bin&#x2F;iterm2-send-zmodem.sh</span><br><span class="line">        Instant: checked</span><br><span class="line">2.第二条</span><br><span class="line">        Regular expression: \*\*B00000000000000</span><br><span class="line">        Action: Run Silent Coprocess</span><br><span class="line">        Parameters: &#x2F;usr&#x2F;local&#x2F;bin&#x2F;iterm2-recv-zmodem.sh</span><br><span class="line">        Instant: checked</span><br></pre></td></tr></table></div></figure>

<p>
        <img   class="lazyload lazyload-gif"
          src="/images/loading.svg" data-src="https://cdn.qiniu.wenzuo.net/catch6.github.io/20201214100209.png" >
      </p>
</li>
</ol>

        <h3 id="iterm2-recv-zmodem-sh"   >
          <a href="#iterm2-recv-zmodem-sh" class="heading-link"><i class="fas fa-link"></i></a>iterm2-recv-zmodem.sh</h3>
      <figure class="highlight sh"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># 这个脚本来自 github，https://github.com/aikuyun/iterm2-zmodem/blob/master/iterm2-recv-zmodem.sh</span></span><br><span class="line"></span><br><span class="line">osascript -e <span class="string">&#x27;tell application &quot;iTerm2&quot; to version&#x27;</span> &gt; /dev/null 2&gt;&amp;1 &amp;&amp; NAME=iTerm2 || NAME=iTerm</span><br><span class="line"><span class="keyword">if</span> [[ <span class="variable">$NAME</span> = <span class="string">&quot;iTerm&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">	FILE=$(osascript -e <span class="string">&#x27;tell application &quot;iTerm&quot; to activate&#x27;</span> -e <span class="string">&#x27;tell application &quot;iTerm&quot; to set thefile to choose folder with prompt &quot;Choose a folder to place received files in&quot;&#x27;</span> -e <span class="string">&quot;do shell script (\&quot;echo \&quot;&amp;(quoted form of POSIX path of thefile as Unicode text)&amp;\&quot;\&quot;)&quot;</span>)</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">	FILE=$(osascript -e <span class="string">&#x27;tell application &quot;iTerm2&quot; to activate&#x27;</span> -e <span class="string">&#x27;tell application &quot;iTerm2&quot; to set thefile to choose folder with prompt &quot;Choose a folder to place received files in&quot;&#x27;</span> -e <span class="string">&quot;do shell script (\&quot;echo \&quot;&amp;(quoted form of POSIX path of thefile as Unicode text)&amp;\&quot;\&quot;)&quot;</span>)</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [[ <span class="variable">$FILE</span> = <span class="string">&quot;&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">	<span class="built_in">echo</span> Cancelled.</span><br><span class="line">	<span class="comment"># Send ZModem cancel</span></span><br><span class="line">	<span class="built_in">echo</span> -e \\x18\\x18\\x18\\x18\\x18</span><br><span class="line">	sleep 1</span><br><span class="line">	<span class="built_in">echo</span></span><br><span class="line">	<span class="built_in">echo</span> \<span class="comment"># Cancelled transfer</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">	<span class="built_in">cd</span> <span class="string">&quot;<span class="variable">$FILE</span>&quot;</span></span><br><span class="line">	/usr/<span class="built_in">local</span>/bin/rz -E -e -b --bufsize 4096</span><br><span class="line">	sleep 1</span><br><span class="line">	<span class="built_in">echo</span></span><br><span class="line">	<span class="built_in">echo</span></span><br><span class="line">	<span class="built_in">echo</span> \<span class="comment"># Sent \-\&gt; $FILE</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></div></figure>


        <h3 id="iterm2-send-zmodem-sh"   >
          <a href="#iterm2-send-zmodem-sh" class="heading-link"><i class="fas fa-link"></i></a>iterm2-send-zmodem.sh</h3>
      <figure class="highlight sh"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># 这个脚本来自 github，https://github.com/aikuyun/iterm2-zmodem/blob/master/iterm2-send-zmodem.sh</span></span><br><span class="line"></span><br><span class="line">osascript -e <span class="string">&#x27;tell application &quot;iTerm2&quot; to version&#x27;</span> &gt; /dev/null 2&gt;&amp;1 &amp;&amp; NAME=iTerm2 || NAME=iTerm</span><br><span class="line"><span class="keyword">if</span> [[ <span class="variable">$NAME</span> = <span class="string">&quot;iTerm&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">	FILE=`osascript -e <span class="string">&#x27;tell application &quot;iTerm&quot; to activate&#x27;</span> -e <span class="string">&#x27;tell application &quot;iTerm&quot; to set thefile to choose file with prompt &quot;Choose a file to send&quot;&#x27;</span> -e <span class="string">&quot;do shell script (\&quot;echo \&quot;&amp;(quoted form of POSIX path of thefile as Unicode text)&amp;\&quot;\&quot;)&quot;</span>`</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">	FILE=`osascript -e <span class="string">&#x27;tell application &quot;iTerm2&quot; to activate&#x27;</span> -e <span class="string">&#x27;tell application &quot;iTerm2&quot; to set thefile to choose file with prompt &quot;Choose a file to send&quot;&#x27;</span> -e <span class="string">&quot;do shell script (\&quot;echo \&quot;&amp;(quoted form of POSIX path of thefile as Unicode text)&amp;\&quot;\&quot;)&quot;</span>`</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"><span class="keyword">if</span> [[ <span class="variable">$FILE</span> = <span class="string">&quot;&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">	<span class="built_in">echo</span> Cancelled.</span><br><span class="line">	<span class="comment"># Send ZModem cancel</span></span><br><span class="line">	<span class="built_in">echo</span> -e \\x18\\x18\\x18\\x18\\x18</span><br><span class="line">	sleep 1</span><br><span class="line">	<span class="built_in">echo</span></span><br><span class="line">	<span class="built_in">echo</span> \<span class="comment"># Cancelled transfer</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">	/usr/<span class="built_in">local</span>/bin/sz <span class="string">&quot;<span class="variable">$FILE</span>&quot;</span> --escape --binary --bufsize 4096</span><br><span class="line">	sleep 1</span><br><span class="line">	<span class="built_in">echo</span></span><br><span class="line">	<span class="built_in">echo</span> \<span class="comment"># Received $FILE</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></div></figure>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/21/springboot-param-validate.html">SpringBoot 参数校验</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-21</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h2 id="准备工作"   >
          <a href="#准备工作" class="heading-link"><i class="fas fa-link"></i></a>准备工作</h2>
      <p>引入相关依赖</p>
<figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-validation<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="Bean-Validation-中的约束"   >
          <a href="#Bean-Validation-中的约束" class="heading-link"><i class="fas fa-link"></i></a>Bean Validation 中的约束</h2>
      <div class="table-container"><table>
<thead>
<tr>
<th>约束</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>@Null</td>
<td>被注释的元素必须为 null</td>
</tr>
<tr>
<td>@NotNull</td>
<td>被注释的元素必须不为 null</td>
</tr>
<tr>
<td>@AssertTrue</td>
<td>被注释的元素必须为 true</td>
</tr>
<tr>
<td>@AssertFalse</td>
<td>被注释的元素必须为 false</td>
</tr>
<tr>
<td>@Min(value)</td>
<td>被注释的元素必须是一个数字，其值必须大于等于指定的最小值</td>
</tr>
<tr>
<td>@Max(value)</td>
<td>被注释的元素必须是一个数字，其值必须小于等于指定的最大值</td>
</tr>
<tr>
<td>@DecimalMin(value)</td>
<td>被注释的元素必须是一个数字，其值必须大于等于指定的最小值</td>
</tr>
<tr>
<td>@DecimalMax(value)</td>
<td>被注释的元素必须是一个数字，其值必须小于等于指定的最大值</td>
</tr>
<tr>
<td>@Size(max, min)</td>
<td>被注释的元素的大小必须在指定的范围内</td>
</tr>
<tr>
<td>@Digits (integer, fraction)</td>
<td>被注释的元素必须是一个数字，其值必须在可接受的范围内</td>
</tr>
<tr>
<td>@Past</td>
<td>被注释的元素必须是一个过去的日期</td>
</tr>
<tr>
<td>@Future</td>
<td>被注释的元素必须是一个将来的日期</td>
</tr>
<tr>
<td>@Pattern(value)</td>
<td>被注释的元素必须符合指定的正则表达式</td>
</tr>
</tbody></table></div>

        <h2 id="Hibernate-Validator-附加的约束"   >
          <a href="#Hibernate-Validator-附加的约束" class="heading-link"><i class="fas fa-link"></i></a>Hibernate Validator 附加的约束</h2>
      <div class="table-container"><table>
<thead>
<tr>
<th>约束</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>@Email</td>
<td>被注释的元素必须是电子邮箱地址</td>
</tr>
<tr>
<td>@Length</td>
<td>被注释的字符串的大小必须在指定的范围内</td>
</tr>
<tr>
<td>@NotEmpty</td>
<td>被注释的字符串的必须非空</td>
</tr>
<tr>
<td>@Range</td>
<td>被注释的元素必须在合适的范围内</td>
</tr>
</tbody></table></div>

        <h2 id="代码中校验"   >
          <a href="#代码中校验" class="heading-link"><i class="fas fa-link"></i></a>代码中校验</h2>
      <p>spring 中可以直接从 aop 容器中获取</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> Validator validator;</span><br></pre></td></tr></table></div></figure>

<p>通过工厂方法获取</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ValidatorFactory factory = Validation.buildDefaultValidatorFactory();</span><br><span class="line">Validator validator = factory.getValidator();</span><br><span class="line">Set&lt;ConstraintViolation&lt;DemoDTO&gt;&gt; violations = validator.validate(dto);</span><br></pre></td></tr></table></div></figure>


        <h2 id="Validated-与-Valid-的简单对比说明"   >
          <a href="#Validated-与-Valid-的简单对比说明" class="heading-link"><i class="fas fa-link"></i></a>@Validated 与@Valid 的简单对比说明</h2>
      <p>@Valid 注解与@Validated 注解功能大部分类似；两者的不同主要在于:</p>
<ul>
<li>@Valid 属于 javax 下的，而@Validated 属于 Spring 下</li>
<li>@Valid 支持嵌套校验，而@Validated 不支持</li>
<li>@Validated 支持分组，而@Valid 不支持</li>
</ul>

        <h2 id="普通方法校验参数"   >
          <a href="#普通方法校验参数" class="heading-link"><i class="fas fa-link"></i></a>普通方法校验参数</h2>
      <p>除了验证接口，我们还可以验证普通的方法，首先在需要验证的方法所在类上面增加注解 @Validated</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Validated</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DemoService</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">demo</span><span class="params">(<span class="meta">@Valid</span> DemoDTO dto)</span> </span>&#123;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>注意：</strong></p>
<ul>
<li>基于 aop 机制，被验证的方法需要注册为组件</li>
<li>只能在类上面增加注解@Validated，不能在单个方法上</li>
<li>抛出的异常为 ConstraintViolationException，需要单独拦截，示例：</li>
</ul>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="meta">@ExceptionHandler(ConstraintViolationException.class)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> HttpResponse <span class="title">handle</span><span class="params">(ConstraintViolationException e)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> HttpResponse.builder().code(<span class="number">500</span>).msg(</span><br><span class="line">        e.getConstraintViolations()</span><br><span class="line">        .stream()</span><br><span class="line">        .findFirst()</span><br><span class="line">        .map(ConstraintViolation::getMessage)</span><br><span class="line">        .orElse(<span class="string">&quot;参数校验失败&quot;</span>)).build();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="嵌套验证"   >
          <a href="#嵌套验证" class="heading-link"><i class="fas fa-link"></i></a>嵌套验证</h2>
      <p>当我们要验证的类 DemoBO 有成员属性为 OtherObject，对 OtherObject 中的属性进行校验，需要在 DemoBO 的成员属性 OtherObject 之上加上 @Valid</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DemoBO</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Valid</span></span><br><span class="line">    <span class="keyword">private</span> OtherObject otherObject;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="分组校验"   >
          <a href="#分组校验" class="heading-link"><i class="fas fa-link"></i></a>分组校验</h2>
      <p>在很多时候，同一个模型可能会在多处被用到，但每处的校验场景又不一定相同(如：新增用户接口、修改用户接口,参数都是 User 模型，在新增时 User 中 name 字段不能为空，userNo 字段可以为空；在修改时 User 中 name 字段可以为空，userNo 字段不能为空)。我们可以用 groups 来实现:<strong>同一个模型在不同场景下，(动态区分)校验模型中的不同字段。</strong></p>
<p>创建分组 Create 和 Update 继承 Default</p>
<p>继承 Default 并不是必须的。只是说，如果继承了 Default，那么@Validated(value = Create.class)的校验范畴就为【Create】和【Default】；如果没继承 Default，那么@Validated(value = Create.class)的校验范畴只为【Create】，而@Validated(value = {Create.class, Default.class})的校验范畴才为【Create】【Default】。</p>
<p>Default 组和无参构造机制类似，当没有指定分组时，会默认当前校验属于 Default 组，但是一旦主动给当前校验指定<br>了分组(如上图中的 name 字段，主动指定了属于 Create 组)，那么就不会再额外指定属于 Default 组了。<br>当然，也可以画蛇添足的主动指定所属分组为 Default。</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javax.validation.groups.Default;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Create</span> <span class="keyword">extends</span> <span class="title">Default</span></span>&#123;&#125;</span><br></pre></td></tr></table></div></figure>

<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javax.validation.groups.Default;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Update</span> <span class="keyword">extends</span> <span class="title">Default</span></span>&#123;&#125;</span><br></pre></td></tr></table></div></figure>

<p>创建实体类 Student</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Student</span></span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="meta">@NotNull(groups=Update.class)</span></span><br><span class="line">  <span class="keyword">private</span> Long id;</span><br><span class="line"></span><br><span class="line">  <span class="meta">@NotEmpty(groups=Create.class)</span></span><br><span class="line">  <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">  <span class="meta">@NotEmpty</span></span><br><span class="line">  <span class="keyword">private</span> Integer age;</span><br><span class="line"></span><br><span class="line">  <span class="meta">@NotEmpty(groups=Default.class)</span> <span class="comment">// 等价于 @NotEmpty</span></span><br><span class="line">  <span class="keyword">private</span> Integer gender;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/18/maven-multiple-repository.html">maven多仓库配置 - 公司仓库与阿里云仓库共存</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-18</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt"><p>以下操作在 maven 配置文件 <code>settings.xml</code> 中修改</p>

        <h2 id="配置公司账户信息-server"   >
          <a href="#配置公司账户信息-server" class="heading-link"><i class="fas fa-link"></i></a>配置公司账户信息 server</h2>
      <figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">servers</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">server</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">id</span>&gt;</span>nexus<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">username</span>&gt;</span>xxx<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">password</span>&gt;</span>xxx<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">server</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">servers</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="删除掉原来的-mirror"   >
          <a href="#删除掉原来的-mirror" class="heading-link"><i class="fas fa-link"></i></a>删除掉原来的 mirror</h2>
      <figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">mirrors</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mirrors</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="配置公司和阿里云-profile"   >
          <a href="#配置公司和阿里云-profile" class="heading-link"><i class="fas fa-link"></i></a>配置公司和阿里云 profile</h2>
      <figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">profiles</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">profile</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">id</span>&gt;</span>nexus<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">repositories</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">repository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>nexus-pub<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>private-nexus<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://192.168.50.1:8899/nexus/content/groups/public/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">releases</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">enabled</span>&gt;</span>true<span class="tag">&lt;/<span class="name">enabled</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">releases</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">snapshots</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">enabled</span>&gt;</span>true<span class="tag">&lt;/<span class="name">enabled</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">updatePolicy</span>&gt;</span>always<span class="tag">&lt;/<span class="name">updatePolicy</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">snapshots</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">repository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">repositories</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">pluginRepositories</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pluginRepository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>nexus-pub<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>private nexus<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://192.168.50.1:8899/nexus/content/groups/public/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">releases</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">enabled</span>&gt;</span>true<span class="tag">&lt;/<span class="name">enabled</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">releases</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">snapshots</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">enabled</span>&gt;</span>true<span class="tag">&lt;/<span class="name">enabled</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">updatePolicy</span>&gt;</span>always<span class="tag">&lt;/<span class="name">updatePolicy</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">snapshots</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">pluginRepository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">pluginRepositories</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">profile</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">profile</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">id</span>&gt;</span>aliyun<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">repositories</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">repository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>central<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://maven.aliyun.com/nexus/content/groups/public/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">repository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">repositories</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">pluginRepositories</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pluginRepository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>central<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://maven.aliyun.com/nexus/content/groups/public/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">pluginRepository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">pluginRepositories</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">profile</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">profiles</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="配置-activeProfiles"   >
          <a href="#配置-activeProfiles" class="heading-link"><i class="fas fa-link"></i></a>配置 activeProfiles</h2>
      <figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">activeProfiles</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">activeProfile</span>&gt;</span>nexus<span class="tag">&lt;/<span class="name">activeProfile</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">activeProfile</span>&gt;</span>aliyun<span class="tag">&lt;/<span class="name">activeProfile</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">activeProfiles</span>&gt;</span></span><br></pre></td></tr></table></div></figure>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/17/http-status-code.html">http 状态码大全</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-17</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h2 id="1xx-消息"   >
          <a href="#1xx-消息" class="heading-link"><i class="fas fa-link"></i></a>1xx 消息</h2>
      <p>▪ 100 Continue<br>▪ 101 Switching Protocols<br>▪ 102 Processing</p>

        <h2 id="2xx-成功"   >
          <a href="#2xx-成功" class="heading-link"><i class="fas fa-link"></i></a>2xx 成功</h2>
      <p>▪ 200 OK<br>▪ 201 Created<br>▪ 202 Accepted<br>▪ 203 Non-Authoritative Information<br>▪ 204 No Content<br>▪ 205 Reset Content<br>▪ 206 Partial Content<br>▪ 207 Multi-Status</p>

        <h2 id="3xx-重定向"   >
          <a href="#3xx-重定向" class="heading-link"><i class="fas fa-link"></i></a>3xx 重定向</h2>
      <p>▪ 300 Multiple Choices<br>▪ 301 Moved Permanently<br>▪ 302 Move Temporarily<br>▪ 303 See Other<br>▪ 304 Not Modified<br>▪ 305 Use Proxy<br>▪ 306 Switch Proxy<br>▪ 307 Temporary Redirect</p>

        <h2 id="4xx-请求错误"   >
          <a href="#4xx-请求错误" class="heading-link"><i class="fas fa-link"></i></a>4xx 请求错误</h2>
      <p>▪ 400 Bad Request<br>▪ 401 Unauthorized<br>▪ 402 Payment Required<br>▪ 403 Forbidden<br>▪ 404 Not Found<br>▪ 405 Method Not Allowed<br>▪ 406 Not Acceptable<br>▪ 407 Proxy Authentication Required<br>▪ 408 Request Timeout<br>▪ 409 Conflict<br>▪ 410 Gone<br>▪ 411 Length Required<br>▪ 412 Precondition Failed<br>▪ 413 Request Entity Too Large<br>▪ 414 Request-URI Too Long<br>▪ 415 Unsupported Media Type<br>▪ 416 Requested Range Not Satisfiable<br>▪ 417 Expectation Failed<br>▪ 418 I’m a teapot<br>▪ 421 Misdirected Request<br>▪ 422 Unprocessable Entity<br>▪ 423 Locked<br>▪ 424 Failed Dependency<br>▪ 425 Too Early<br>▪ 426 Upgrade Required<br>▪ 449 Retry With<br>▪ 451 Unavailable For Legal Reasons</p>

        <h2 id="5xx-服务器错误"   >
          <a href="#5xx-服务器错误" class="heading-link"><i class="fas fa-link"></i></a>5xx 服务器错误</h2>
      <p>▪ 500 Internal Server Error<br>▪ 501 Not Implemented<br>▪ 502 Bad Gateway<br>▪ 503 Service Unavailable<br>▪ 504 Gateway Timeout<br>▪ 505 HTTP Version Not Supported<br>▪ 506 Variant Also Negotiates<br>▪ 507 Insufficient Storage<br>▪ 509 Bandwidth Limit Exceeded<br>▪ 510 Not Extended<br>▪ 600 Unparseable Response Headers</p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/17/springboot-starter-kit.html">springboot-starter-kit 企业级脚手架</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-17</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt"><p>本文将从零开始搭建一个 springboot-starter-kit 脚手架项目，以支持当前主流的前后端分离架构，开箱即用，快速开发！</p>

        <h2 id="模块分层"   >
          <a href="#模块分层" class="heading-link"><i class="fas fa-link"></i></a>模块分层</h2>
      <p>api(controller) –&gt; service –&gt; mapper(dao) –&gt; pojo(entity) –&gt; common</p>

        <h2 id="logback-日志处理"   >
          <a href="#logback-日志处理" class="heading-link"><i class="fas fa-link"></i></a>logback 日志处理</h2>
      <p>在 api 模块的 resources 目录下创建 logback-spring.xml</p>
<figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 日志文件存放路径 --&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--    &lt;property name=&quot;logback.dir&quot; value=&quot;/Users/zhanghao/data/@project.name@/log&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">springProperty</span> <span class="attr">scope</span>=<span class="string">&quot;context&quot;</span> <span class="attr">name</span>=<span class="string">&quot;logback.dir&quot;</span> <span class="attr">source</span>=<span class="string">&quot;logging.logback.dir&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 彩色日志依赖的渲染类 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">conversionRule</span> <span class="attr">conversionWord</span>=<span class="string">&quot;clr&quot;</span></span></span><br><span class="line"><span class="tag">                    <span class="attr">converterClass</span>=<span class="string">&quot;org.springframework.boot.logging.logback.ColorConverter&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">conversionRule</span> <span class="attr">conversionWord</span>=<span class="string">&quot;wex&quot;</span></span></span><br><span class="line"><span class="tag">                    <span class="attr">converterClass</span>=<span class="string">&quot;org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">conversionRule</span> <span class="attr">conversionWord</span>=<span class="string">&quot;wEx&quot;</span></span></span><br><span class="line"><span class="tag">                    <span class="attr">converterClass</span>=<span class="string">&quot;org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 控制台日志渲染格式 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;CONSOLE_LOG_PATTERN&quot;</span></span></span><br><span class="line"><span class="tag">              <span class="attr">value</span>=<span class="string">&quot;$&#123;CONSOLE_LOG_PATTERN:-%clr(%d&#123;$&#123;LOG_DATEFORMAT_PATTERN:-HH:mm:ss.SSS&#125;&#125;)&#123;faint&#125; %clr($&#123;LOG_LEVEL_PATTERN:-%5p&#125;) %clr($&#123;PID:- &#125;)&#123;magenta&#125; %clr(-)&#123;faint&#125; %clr([%13.13t])&#123;faint&#125; %clr(%-40.40logger&#123;39&#125;)&#123;cyan&#125; %clr(:)&#123;faint&#125; %m%n$&#123;LOG_EXCEPTION_CONVERSION_WORD:-%wEx&#125;&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 日志文件渲染格式 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;FILE_LOG_PATTERN&quot;</span></span></span><br><span class="line"><span class="tag">              <span class="attr">value</span>=<span class="string">&quot;$&#123;FILE_LOG_PATTERN:-%d&#123;$&#123;LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS&#125;&#125; $&#123;LOG_LEVEL_PATTERN:-%5p&#125; $&#123;PID:- &#125; - [%13.13t] %-40.40logger&#123;39&#125; : %m%n$&#123;LOG_EXCEPTION_CONVERSION_WORD:-%wEx&#125;&#125;&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!-- 输出到控制台 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">&quot;consoleLog&quot;</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.core.ConsoleAppender&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 日志格式 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">layout</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.classic.PatternLayout&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">pattern</span>&gt;</span></span><br><span class="line">                $&#123;CONSOLE_LOG_PATTERN&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">layout</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 日志等级 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">filter</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.classic.filter.ThresholdFilter&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">level</span>&gt;</span>INFO<span class="tag">&lt;/<span class="name">level</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">filter</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">&quot;fileInfoLog&quot;</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.core.rolling.RollingFileAppender&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 如果只是想要 Info 级别的日志，只是过滤 info 还是会输出 Error 日志，因为 Error 的级别高，</span></span><br><span class="line"><span class="comment">        所以我们使用下面的策略，可以避免输出 Error 的日志 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">filter</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.classic.filter.LevelFilter&quot;</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!-- 过滤 Error --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">level</span>&gt;</span>ERROR<span class="tag">&lt;/<span class="name">level</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!-- 匹配到就禁止 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">onMatch</span>&gt;</span>DENY<span class="tag">&lt;/<span class="name">onMatch</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!-- 没有匹配到就允许 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">onMismatch</span>&gt;</span>ACCEPT<span class="tag">&lt;/<span class="name">onMismatch</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">filter</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 日志名称，如果没有File 属性，那么只会使用FileNamePattern的文件路径规则</span></span><br><span class="line"><span class="comment">            如果同时有&lt;File&gt;和&lt;FileNamePattern&gt;，那么当天日志是&lt;File&gt;，明天会自动把今天</span></span><br><span class="line"><span class="comment">            的日志改名为今天的日期。即，&lt;File&gt; 的日志都是当天的。--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">File</span>&gt;</span>$&#123;logback.dir&#125;/info.log<span class="tag">&lt;/<span class="name">File</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--滚动策略，按照时间滚动 TimeBasedRollingPolicy--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">rollingPolicy</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&quot;</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">FileNamePattern</span>&gt;</span>$&#123;logback.dir&#125;/info.%d&#123;yyyy-MM-dd&#125;.log<span class="tag">&lt;/<span class="name">FileNamePattern</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--只保留最近90天的日志--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">maxHistory</span>&gt;</span>90<span class="tag">&lt;/<span class="name">maxHistory</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--用来指定日志文件的上限大小，那么到了这个值，就会删除旧的日志--&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--&lt;totalSizeCap&gt;1GB&lt;/totalSizeCap&gt;--&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">rollingPolicy</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--日志输出编码格式化--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">charset</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">charset</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>$&#123;FILE_LOG_PATTERN&#125;<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">&quot;fileErrorLog&quot;</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.core.rolling.RollingFileAppender&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--如果只是想要 Error 级别的日志，那么需要过滤一下，默认是 info 级别的，ThresholdFilter--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">filter</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.classic.filter.ThresholdFilter&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">level</span>&gt;</span>Error<span class="tag">&lt;/<span class="name">level</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">filter</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--日志名称，如果没有File 属性，那么只会使用FileNamePattern的文件路径规则</span></span><br><span class="line"><span class="comment">            如果同时有&lt;File&gt;和&lt;FileNamePattern&gt;，那么当天日志是&lt;File&gt;，明天会自动把今天</span></span><br><span class="line"><span class="comment">            的日志改名为今天的日期。即，&lt;File&gt; 的日志都是当天的。</span></span><br><span class="line"><span class="comment">        --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">File</span>&gt;</span>$&#123;logback.dir&#125;/error.log<span class="tag">&lt;/<span class="name">File</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--滚动策略，按照时间滚动 TimeBasedRollingPolicy--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">rollingPolicy</span> <span class="attr">class</span>=<span class="string">&quot;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&quot;</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">FileNamePattern</span>&gt;</span>$&#123;logback.dir&#125;/error.%d&#123;yyyy-MM-dd&#125;.log<span class="tag">&lt;/<span class="name">FileNamePattern</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--只保留最近90天的日志--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">maxHistory</span>&gt;</span>90<span class="tag">&lt;/<span class="name">maxHistory</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--用来指定日志文件的上限大小，那么到了这个值，就会删除旧的日志--&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--&lt;totalSizeCap&gt;1GB&lt;/totalSizeCap&gt;--&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">rollingPolicy</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--日志输出编码格式化--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">charset</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">charset</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>$&#123;FILE_LOG_PATTERN&#125;<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--指定最基础的日志输出级别--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">&quot;INFO&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- appender 将会添加到这个 logger --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">&quot;consoleLog&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">&quot;fileInfoLog&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">&quot;fileErrorLog&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p>在 application.yml 中添加日志根目录</p>
<figure class="highlight yml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">logback:</span></span><br><span class="line">    <span class="attr">dir:</span> <span class="string">/Users/zhanghao/data/springboot-starter-kit/log</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="统一响应对象"   >
          <a href="#统一响应对象" class="heading-link"><i class="fas fa-link"></i></a>统一响应对象</h2>
      <p>异常对象枚举</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example.common.enums;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 错误码与错误信息枚举类</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhanghao13</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2020/11/17 20:39</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">enum</span> <span class="title">RetEnum</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    OK(<span class="number">200</span>, <span class="string">&quot;成功&quot;</span>),</span><br><span class="line">    BAD_REQUEST(<span class="number">400</span>, <span class="string">&quot;参数错误&quot;</span>),</span><br><span class="line">    UNAUTHORIZED(<span class="number">401</span>, <span class="string">&quot;您未登录或您的登录信息已过期，请重新登录&quot;</span>),</span><br><span class="line">    FORBIDDEN(<span class="number">403</span>, <span class="string">&quot;您没有该权限&quot;</span>),</span><br><span class="line">    NOT_FOUND(<span class="number">404</span>, <span class="string">&quot;您请求的资源未找到&quot;</span>),</span><br><span class="line">    SERVER_ERROR(<span class="number">500</span>, <span class="string">&quot;服务器异常&quot;</span>),</span><br><span class="line">    ;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> code;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> String msg;</span><br><span class="line"></span><br><span class="line">    RetEnum(<span class="keyword">int</span> code, String msg) &#123;</span><br><span class="line">        <span class="keyword">this</span>.code = code;</span><br><span class="line">        <span class="keyword">this</span>.msg = msg;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p>统一响应对象</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example.common;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"><span class="keyword">import</span> lombok.experimental.Accessors;</span><br><span class="line"><span class="keyword">import</span> org.example.common.enums.RetEnum;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 统一响应, 用于返回 json 响应体</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhanghao13</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2020/11/17 20:31</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@Accessors(chain = true)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Ret</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">2665482313176083754L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> code;</span><br><span class="line">    <span class="keyword">private</span> String msg;</span><br><span class="line">    <span class="keyword">private</span> Object data;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">ok</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Ret().setCode(RetEnum.OK.code).setMsg(RetEnum.OK.msg);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">ok</span><span class="params">(Object data)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.ok().setData(data);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">fail</span><span class="params">(<span class="keyword">int</span> code, String msg)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Ret().setCode(code).setMsg(msg);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">fail</span><span class="params">(String msg)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(RetEnum.BAD_REQUEST.code, msg);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">fail</span><span class="params">(RetEnum retEnum)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(retEnum.code, retEnum.msg);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓以下为常用业务失败封装↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">badRequest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(RetEnum.BAD_REQUEST);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">unauthorized</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(RetEnum.UNAUTHORIZED);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">forbidden</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(RetEnum.FORBIDDEN);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">notFound</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(RetEnum.NOT_FOUND);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Ret <span class="title">serverError</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(RetEnum.SERVER_ERROR);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="业务异常类"   >
          <a href="#业务异常类" class="heading-link"><i class="fas fa-link"></i></a>业务异常类</h2>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example.common.exception;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 参数校验异常类</span></span><br><span class="line"><span class="comment"> * 此异常阻止了异常栈追踪信息, 提高了性能, 避免抛出不必要的异常栈, 干扰调试</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhanghao13</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2020/11/18 14:29</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ServiceException</span> <span class="keyword">extends</span> <span class="title">RuntimeException</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">3287961933635362725L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 仅记录异常信息, 不记录 cause by 和 stack trace, 提高性能</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> message 异常信息</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ServiceException</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">          message  异常的描述信息，也就是在打印栈追踪信息时异常类名后面紧跟着的描述字符串</span></span><br><span class="line"><span class="comment">          cause    导致此异常发生的父异常，即追踪信息里的caused by</span></span><br><span class="line"><span class="comment">          enableSuppress   关于异常挂起的参数，这里我们永远设为false即可</span></span><br><span class="line"><span class="comment">          writableStackTrace   表示是否生成栈追踪信息，只要将此参数设为false, 则在构造异常对象时就不会调用fillInStackTrace()</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">super</span>(message, <span class="keyword">null</span>, <span class="keyword">false</span>, <span class="keyword">false</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="全局异常处理"   >
          <a href="#全局异常处理" class="heading-link"><i class="fas fa-link"></i></a>全局异常处理</h2>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example.api.configuration;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.example.common.Ret;</span><br><span class="line"><span class="keyword">import</span> org.example.common.exception.ServiceException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ControllerAdvice;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ExceptionHandler;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 全局统一异常处理类</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhanghao13</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2020/11/18 19:44</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@ControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExceptionConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 业务异常处理器: 如参数错误</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> e 异常对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> Ret</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(ServiceException.class)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Ret <span class="title">handler</span><span class="params">(ServiceException e)</span> </span>&#123;</span><br><span class="line">        log.info(e.getMessage(), e);</span><br><span class="line">        <span class="keyword">return</span> Ret.fail(e.getMessage());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 默认异常处理器</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> e 异常对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> Ret</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExceptionHandler(Exception.class)</span></span><br><span class="line">    <span class="meta">@ResponseBody</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Ret <span class="title">handler</span><span class="params">(Exception e)</span> </span>&#123;</span><br><span class="line">        log.error(e.getMessage(), e);</span><br><span class="line">        <span class="keyword">return</span> Ret.serverError();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="全局请求响应参数及耗时记录"   >
          <a href="#全局请求响应参数及耗时记录" class="heading-link"><i class="fas fa-link"></i></a>全局请求响应参数及耗时记录</h2>
      
        <h2 id="异步调用处理"   >
          <a href="#异步调用处理" class="heading-link"><i class="fas fa-link"></i></a>异步调用处理</h2>
      
        <h2 id="Redis-整合及序列化处理"   >
          <a href="#Redis-整合及序列化处理" class="heading-link"><i class="fas fa-link"></i></a>Redis 整合及序列化处理</h2>
      
        <h2 id="Knife4j-接口文档整合"   >
          <a href="#Knife4j-接口文档整合" class="heading-link"><i class="fas fa-link"></i></a>Knife4j 接口文档整合</h2>
      </div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/14/fix-slow-pasting-caused-by-zsh-autosuggestions.html">修复由于 zsh-autosuggestions 造成的粘贴慢</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-14</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt"><p>使用 <code>zsh</code> 在开启 zsh-autosuggestions 插件的时候，粘贴命令会像打字一样，尤其是长段的命令，需要等很长时间</p>
<p>官方有一个 issues 专门来讨论这个问题：<span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="https://github.com/zsh-users/zsh-autosuggestions/issues/238" >https://github.com/zsh-users/zsh-autosuggestions/issues/238</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>
<p>解决办法：将以下代码粘贴到 <code>.zshrc</code> 文件中即可</p>
<figure class="highlight bash"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># This speeds up pasting w/ autosuggest</span></span><br><span class="line"><span class="comment"># https://github.com/zsh-users/zsh-autosuggestions/issues/238</span></span><br><span class="line"><span class="function"><span class="title">pasteinit</span></span>() &#123;</span><br><span class="line">  OLD_SELF_INSERT=<span class="variable">$&#123;<span class="variable">$&#123;(s.:.)widgets[self-insert]&#125;</span>[2,3]&#125;</span></span><br><span class="line">  <span class="built_in">zle</span> -N self-insert url-quote-magic <span class="comment"># I wonder if you&#x27;d need `.url-quote-magic`?</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">pastefinish</span></span>() &#123;</span><br><span class="line">  <span class="built_in">zle</span> -N self-insert <span class="variable">$OLD_SELF_INSERT</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">zstyle</span> :bracketed-paste-magic paste-init pasteinit</span><br></pre></td></tr></table></div></figure>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/11/java8-stream-api.html">Java8 Stream API</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-11</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt">
        <h2 id="概述"   >
          <a href="#概述" class="heading-link"><i class="fas fa-link"></i></a>概述</h2>
      <p>Stream 作为 Java 8 的一大亮点，它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。Java 8 中的 Stream 是对集合（Collection）对象功能的增强，它专注于对集合对象进行各种非常便利、高效的聚合操作（aggregate operation），或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式，极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作，并发模式能够充分利用多核处理器的优势，使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码，就可以很方便地写出高性能的并发程序。</p>
<p>Stream 就如同一个迭代器（Iterator），单向，不可往复，数据只能遍历一次，遍历过一次后即用尽了，就好比流水从面前流过，一去不复返。</p>
<p>而和迭代器又不同的是，Stream 可以并行化操作，迭代器只能命令式地、串行化操作。顾名思义，当使用串行方式去遍历时，每个 item 读完后再读下一个 item。而使用并行去遍历时，数据会被分成多个段，其中每一个都在不同的线程中处理，然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架（JSR166y）来拆分任务和加速处理过程。</p>
<p>Stream 的另外一大特点是，数据源本身可以是无限的。</p>
<p>获取一个数据源（source）→ 数据转换 → 执行操作获取想要的结果，每次转换原有 Stream 对象不改变，返回一个新的 Stream 对象（可以有多次转换），这就允许对其操作可以像链条一样排列，变成一个管道，如下图所示。</p>
<p>
        <img   class="lazyload lazyload-gif"
          src="/images/loading.svg" data-src="https://cdn.qiniu.wenzuo.net/catch6.github.io/20201112144541.png" >
      </p>

        <h2 id="流的操作类型"   >
          <a href="#流的操作类型" class="heading-link"><i class="fas fa-link"></i></a>流的操作类型</h2>
      <p>流的操作类型分为两种：</p>
<ul>
<li>Intermediate ：一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流，做出某种程度的数据映射/过滤，然后返回一个新的流，交给下一个操作使用。这类操作都是惰性化的（lazy），就是说，仅仅调用到这类方法，并没有真正开始流的遍历。</li>
<li>Terminal ：一个流只能有一个 terminal 操作，当这个操作执行后，流就被使用“光”了，无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行，才会真正开始流的遍历，并且会生成一个结果，或者一个 side effect。</li>
</ul>

        <h2 id="生成-Stream-Source-的几种方式"   >
          <a href="#生成-Stream-Source-的几种方式" class="heading-link"><i class="fas fa-link"></i></a>生成 Stream Source 的几种方式</h2>
      
        <h3 id="Stream"   >
          <a href="#Stream" class="heading-link"><i class="fas fa-link"></i></a>Stream</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">java.util.stream.Stream.empty(T... values)</span><br><span class="line">java.util.stream.Stream.of(T t)</span><br><span class="line">java.util.stream.Stream.of(T... values)</span><br><span class="line">java.util.stream.Stream.iterate(<span class="keyword">final</span> T seed, <span class="keyword">final</span> UnaryOperator&lt;T&gt; f)</span><br><span class="line">java.util.stream.Stream.builder().build()</span><br><span class="line">java.util.stream.Stream.concat(Stream&lt;? extends T&gt; a, Stream&lt;? extends T&gt; b)</span><br><span class="line">java.util.stream.Stream.generate(Supplier&lt;T&gt; s)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以上大多数方法同样适用于</span></span><br><span class="line">java.util.stream.IntStream</span><br><span class="line">java.util.stream.LongStream</span><br><span class="line">java.util.stream.DoubleStream</span><br></pre></td></tr></table></div></figure>


        <h3 id="Collection"   >
          <a href="#Collection" class="heading-link"><i class="fas fa-link"></i></a>Collection</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">java.util.Collection.stream()</span><br><span class="line">java.util.Collection.parallelStream()</span><br></pre></td></tr></table></div></figure>


        <h3 id="Arrays"   >
          <a href="#Arrays" class="heading-link"><i class="fas fa-link"></i></a>Arrays</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java.util.Arrays.stream(T[] array)</span><br></pre></td></tr></table></div></figure>


        <h3 id="Reader"   >
          <a href="#Reader" class="heading-link"><i class="fas fa-link"></i></a>Reader</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java.io.BufferedReader.lines()</span><br></pre></td></tr></table></div></figure>


        <h3 id="Files"   >
          <a href="#Files" class="heading-link"><i class="fas fa-link"></i></a>Files</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">java.nio.file.Files.list(Path dir)</span><br><span class="line">java.nio.file.Files.walk(Path start, <span class="keyword">int</span> maxDepth, FileVisitOption... options)</span><br><span class="line">java.nio.file.Files.walk(Path start, FileVisitOption... options)</span><br><span class="line">java.nio.file.Files.find(Path start, <span class="keyword">int</span> maxDepth, BiPredicate&lt;Path, BasicFileAttributes&gt; matcher, FileVisitOption... options)</span><br><span class="line">java.nio.file.Files.lines(Path path, Charset cs)</span><br><span class="line">java.nio.file.Files.lines(Path path)</span><br></pre></td></tr></table></div></figure>


        <h3 id="Random"   >
          <a href="#Random" class="heading-link"><i class="fas fa-link"></i></a>Random</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">java.util.Random.ints()</span><br><span class="line">java.util.Random.ints(<span class="keyword">long</span> streamSize)</span><br><span class="line">java.util.Random.ints(<span class="keyword">int</span> randomNumberOrigin, <span class="keyword">int</span> randomNumberBound)</span><br><span class="line">java.util.Random.ints(<span class="keyword">long</span> streamSize, <span class="keyword">int</span> randomNumberOrigin, <span class="keyword">int</span> randomNumberBound)</span><br><span class="line"></span><br><span class="line">java.util.Random.longs()</span><br><span class="line">java.util.Random.longs(<span class="keyword">long</span> streamSize)</span><br><span class="line">java.util.Random.longs(<span class="keyword">long</span> randomNumberOrigin, <span class="keyword">long</span> randomNumberBound)</span><br><span class="line">java.util.Random.longs(<span class="keyword">long</span> streamSize, <span class="keyword">long</span> randomNumberOrigin, <span class="keyword">long</span> randomNumberBound)</span><br><span class="line"></span><br><span class="line">java.util.Random.doubles()</span><br><span class="line">java.util.Random.doubles(<span class="keyword">long</span> streamSize)</span><br><span class="line">java.util.Random.doubles(<span class="keyword">double</span> randomNumberOrigin, <span class="keyword">double</span> randomNumberBound)</span><br><span class="line">java.util.Random.doubles(<span class="keyword">long</span> streamSize, <span class="keyword">double</span> randomNumberOrigin, <span class="keyword">double</span> randomNumberBound)</span><br></pre></td></tr></table></div></figure>


        <h3 id="其他"   >
          <a href="#其他" class="heading-link"><i class="fas fa-link"></i></a>其他</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">java.util.BitSet.stream()</span><br><span class="line">java.util.regex.Pattern.splitAsStream(<span class="keyword">final</span> CharSequence input)</span><br><span class="line">java.util.jar.JarFile.stream()</span><br></pre></td></tr></table></div></figure>


        <h2 id="Stream-常用操作举例"   >
          <a href="#Stream-常用操作举例" class="heading-link"><i class="fas fa-link"></i></a>Stream 常用操作举例</h2>
      
        <h3 id="准备工作"   >
          <a href="#准备工作" class="heading-link"><i class="fas fa-link"></i></a>准备工作</h3>
      <p>首先创建 <code>User</code> 实体类</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line">    <span class="keyword">private</span> BigDecimal money;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p>然后添加一些测试数据</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">List&lt;User&gt; userList=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">User user1=<span class="keyword">new</span> User(<span class="number">1L</span>,<span class="string">&quot;user1&quot;</span>,<span class="number">15</span>, BigDecimal.valueOf(<span class="number">100.55</span>));</span><br><span class="line">User user2=<span class="keyword">new</span> User(<span class="number">2L</span>,<span class="string">&quot;user2&quot;</span>,<span class="number">16</span>, BigDecimal.valueOf(<span class="number">200.14</span>));</span><br><span class="line">User user3=<span class="keyword">new</span> User(<span class="number">3L</span>,<span class="string">&quot;user3&quot;</span>,<span class="number">17</span>, BigDecimal.valueOf(<span class="number">300.00</span>));</span><br><span class="line">User user4=<span class="keyword">new</span> User(<span class="number">4L</span>,<span class="string">&quot;user4&quot;</span>,<span class="number">18</span>, BigDecimal.valueOf(<span class="number">400.89</span>));</span><br><span class="line">User user5=<span class="keyword">new</span> User(<span class="number">5L</span>,<span class="string">&quot;user5&quot;</span>,<span class="number">19</span>, BigDecimal.valueOf(<span class="number">500.66</span>));</span><br><span class="line"></span><br><span class="line">userList.add(user1);</span><br><span class="line">userList.add(user2);</span><br><span class="line">userList.add(user3);</span><br><span class="line">userList.add(user4);</span><br><span class="line">userList.add(user5);</span><br><span class="line"></span><br><span class="line">Stream&lt;User&gt; userStream = userList.stream();</span><br></pre></td></tr></table></div></figure>


        <h3 id="排序"   >
          <a href="#排序" class="heading-link"><i class="fas fa-link"></i></a>排序</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    List&lt;User&gt; users;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 正序</span></span><br><span class="line">    users = userList.stream().sorted(Comparator.comparing(User::getAge))</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    users.forEach(System.out::println);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 倒序</span></span><br><span class="line">    users = userList.stream().sorted(Comparator.comparing(User::getAge).reversed())</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    users.forEach(System.out::println);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 多重排序</span></span><br><span class="line">    users = userList.stream().sorted(</span><br><span class="line">            Comparator.comparing(User::getAge)</span><br><span class="line">                    .thenComparing(User::getId).reversed()</span><br><span class="line">    )</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    users.forEach(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="转换"   >
          <a href="#转换" class="heading-link"><i class="fas fa-link"></i></a>转换</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    List&lt;String&gt; names;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 可以自由对 user 做转换</span></span><br><span class="line">    names = userList.stream().map(user -&gt; user.getName()).collect(Collectors.toList());</span><br><span class="line">    names.forEach(System.out::println);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 上面写法可以简写如下</span></span><br><span class="line">    names = userList.stream().map(User::getName).collect(Collectors.toList());</span><br><span class="line">    names.forEach(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="处理"   >
          <a href="#处理" class="heading-link"><i class="fas fa-link"></i></a>处理</h3>
      <p><strong>注意 peek 与 map 的区别是:</strong><br><strong>peek 操作 一般用于不想改变流中元素本身的类型或者只想操作元素的内部状态时；</strong><br><strong>而 map 则用于改变流中元素本身类型，即从元素中派生出另一种类型的操作。</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    List&lt;String&gt; names;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 可以自由对 user 属性做修改</span></span><br><span class="line">    names = userList.stream().peek(user -&gt; user.setName(<span class="string">&quot;小名&quot;</span>)).collect(Collectors.toList());</span><br><span class="line">    names.forEach(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="分组"   >
          <a href="#分组" class="heading-link"><i class="fas fa-link"></i></a>分组</h3>
      <p>可以针对对象的某一属性进行分组，比如根据年龄分组</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// lambda 表达式的返回值作为 key, List&lt;User&gt; 作为 value</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//根据年龄转换为 map</span></span><br><span class="line">    Map&lt;Integer, List&lt;User&gt;&gt; map1 = userList.stream().collect(Collectors.groupingBy(User::getAge));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 根据年龄段转换为 map</span></span><br><span class="line">    Map&lt;String, List&lt;User&gt;&gt; map2 = userList.stream().collect(Collectors.groupingBy(user -&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (user.getAge() &lt;= <span class="number">17</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;少年&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (user.getAge() &lt;= <span class="number">40</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;青年&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (user.getAge() &lt;= <span class="number">65</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;中年&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;老年&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="转-Map"   >
          <a href="#转-Map" class="heading-link"><i class="fas fa-link"></i></a>转 Map</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    Map&lt;Integer, User&gt; map;</span><br><span class="line"></span><br><span class="line">    map = userList.stream().collect(Collectors.toMap(user -&gt; user.getAge(), user -&gt; user));</span><br><span class="line">    <span class="comment">// 上面写法可以简写如下</span></span><br><span class="line">    map = userList.stream().collect(Collectors.toMap(User::getAge, user -&gt; user));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 需要注意的是,以上写法可能会遇到 key 冲突问题</span></span><br><span class="line">    <span class="comment">// 这里当 key 冲突时舍弃 id 小的, 取 id 大的</span></span><br><span class="line">    map = userList.stream().collect(Collectors.toMap(User::getAge, user -&gt; user, (user1, user2) -&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (user1.getId() &gt; user2.getId()) &#123;</span><br><span class="line">            <span class="keyword">return</span> user1;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> user2;</span><br><span class="line">    &#125;));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="过滤"   >
          <a href="#过滤" class="heading-link"><i class="fas fa-link"></i></a>过滤</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    List&lt;User&gt; users;</span><br><span class="line"></span><br><span class="line">    users = userList.stream().filter(user -&gt; user.getAge() &gt;= <span class="number">18</span>)</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line">    users.forEach(System.out::println);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 可以进行展开对 user 做复杂判断</span></span><br><span class="line">    users = userList.stream().filter(user -&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (user.getAge() &gt; <span class="number">60</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;).collect(Collectors.toList());</span><br><span class="line">    users.forEach(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="去重"   >
          <a href="#去重" class="heading-link"><i class="fas fa-link"></i></a>去重</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 根据 id 去重</span></span><br><span class="line">    List&lt;User&gt; unique = userList.stream().collect(</span><br><span class="line">            Collectors.collectingAndThen(</span><br><span class="line">                    Collectors.toCollection(() -&gt; <span class="keyword">new</span> TreeSet&lt;&gt;(Comparator.comparing(User::getId))), ArrayList::<span class="keyword">new</span>)</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="求和"   >
          <a href="#求和" class="heading-link"><i class="fas fa-link"></i></a>求和</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// int 类型</span></span><br><span class="line">    <span class="keyword">int</span> sumAge = userList.stream().mapToInt(User::getAge).sum();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 对于高精度数值求和, 可以使用 reduce</span></span><br><span class="line">    Optional&lt;BigDecimal&gt; decimalOptional = userList.stream().map(User::getMoney)</span><br><span class="line">            .reduce(BigDecimal::add);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (decimalOptional.isPresent()) &#123;</span><br><span class="line">        BigDecimal sumMoney = decimalOptional.get();</span><br><span class="line">        System.out.println(sumMoney);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;参数错误: money 不能为 null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 设置初始值可以避免返回 Optional</span></span><br><span class="line">    BigDecimal sumMoney = userList.stream().map(User::getMoney)</span><br><span class="line">            .reduce(BigDecimal.ZERO, BigDecimal::add);</span><br><span class="line">    System.out.println(sumMoney);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="查找最大-小值"   >
          <a href="#查找最大-小值" class="heading-link"><i class="fas fa-link"></i></a>查找最大/小值</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">(List&lt;User&gt; userList)</span> </span>&#123;</span><br><span class="line">    Optional&lt;User&gt; maxAgeUser = userList.stream().max(Comparator.comparing(User::getAge));</span><br><span class="line">    maxAgeUser.ifPresent(System.out::println);</span><br><span class="line"></span><br><span class="line">    Optional&lt;User&gt; minAgeUser = userList.stream().min(Comparator.comparing(User::getAge));</span><br><span class="line">    minAgeUser.ifPresent(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="取交集-并集-差集-去重并集"   >
          <a href="#取交集-并集-差集-去重并集" class="heading-link"><i class="fas fa-link"></i></a>取交集/并集/差集/去重并集</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">example</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    List&lt;Integer&gt; list1 = Arrays.asList(<span class="number">1</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">8</span>, <span class="number">9</span>, <span class="number">10</span>);</span><br><span class="line">    List&lt;Integer&gt; list2 = Arrays.asList(<span class="number">2</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">9</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 一般有filter 操作时，不用并行流parallelStream ,如果用的话可能会导致线程安全问题</span></span><br><span class="line"></span><br><span class="line">    List&lt;Integer&gt; list;</span><br><span class="line">    <span class="comment">// 交集 	拓展：list2里面如果是对象，则需要提取每个对象的某一属性组成新的list,多个条件则为多个list</span></span><br><span class="line">    list = list1.stream().filter(item -&gt; list2.contains(item)).collect(Collectors.toList());</span><br><span class="line">    <span class="comment">// 上面可简写如下</span></span><br><span class="line">    list = list1.stream().filter(list2::contains).collect(Collectors.toList());</span><br><span class="line">    System.out.println(<span class="string">&quot;---得到交集 intersection---&quot;</span>);</span><br><span class="line">    list.parallelStream().forEach(System.out::println);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 差集 (list1 - list2)	同上拓展</span></span><br><span class="line">    list = list1.stream().filter(item -&gt; !list2.contains(item)).collect(Collectors.toList());</span><br><span class="line">    System.out.println(<span class="string">&quot;---得到差集 reduce (list1 - list2)---&quot;</span>);</span><br><span class="line">    list.parallelStream().forEach(System.out::println);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/10/jetbrains-activation.html">Jetbrains 系列产品激活</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-10</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt"><p>首先下载激活文件：<span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="https://cloud.wenzuo.net/Tools/jetbrains-agent-latest_3.2.zip" >https://cloud.wenzuo.net/Tools/jetbrains-agent-latest_3.2.zip</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>
<p>解压下载的破解补丁，将「破解补丁」文件夹下面的 jetbrains-agent.zip 拖拽到你喜欢的位置（此文件未来不能删除！）</p>
<p>运行你的 IDE，进行基本的配置后会弹出激活窗口，选择 Evaluate for free，然后点击 Evaluate 按钮。（如果试用过期请下载 App Cleaner &amp; Uninstaller Pro，用它卸载干净后再安装就可以了。）</p>
<p>安装插件-&gt;点击齿轮按钮-&gt;选择从硬盘安装-&gt;选择刚才解压后的 jetbrains-agent.zip-&gt;Restart-IDE</p>
<p>重启完成后，会弹出配置助手，配置助手会提示您，粘贴下面的安装参数，选择默认的 Activation Code 来激活，点击为 IDEA 安装，看到成功提示，点击重启即可</p>
<figure class="highlight plain"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">KC4CPs&#x2F;mH19e7ze1GXfrQH1uVsZ+i1bDpeffO9FzA7pligqeLiXrrrm+IQugrHMlTOo3VZRzlhXOWCtetc6N0Q2n3BONIBwZP&#x2F;1AJqid6e3pcqbVl7PLzMpWfTsWPcE8JkXhlopYgIADMSTwkm2MwMkPCkBiHAXAfJxwzoOgmIE</span><br></pre></td></tr></table></div></figure>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/10/register-free-domain.html">注册免费域名</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-10</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt"><p>本文将讲述如何通过 Freenom 注册免费域名</p>
<p>首先打开其注册网址：<span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="http://www.freenom.com/zh/index.html" >http://www.freenom.com/zh/index.html</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>
<p>输入一个域名，点击检测可用性，勾选喜欢的域名，<br>
        <img   class="lazyload lazyload-gif"
          src="/images/loading.svg" data-src="https://cdn.qiniu.wenzuo.net/catch6.github.io/20201110212449.png" >
      </p>
<p>按照提示注册即可</p>
<p><strong>注意：在注册过程中，在页面下方会显示你 ip 地址，需要把这个 ip 地址复制出来，打开 <span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="http://en.ipip.net/ip.html" >http://en.ipip.net/ip.html</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span> 粘贴这个 ip 地址，得到“国家 州 城市”信息，这个信息用于填写个人资料，一定要按照这个填写，不然在提交域名订单的时候，会提示无法创建域名</strong></p>
<p>注册完成后可以在 Services-&gt;My Domains 下面看到自己注册的域名，点击 manage domain 即可进入域名管理，按如下图可以自定义 DNS 服务器<br>
        <img   class="lazyload lazyload-gif"
          src="/images/loading.svg" data-src="https://cdn.qiniu.wenzuo.net/catch6.github.io/20201110213452.png" >
      </p>
</div></div></article><article class="postlist-item post"><header class="post-header"><h1 class="post-title"><a class="post-title__link" href="/2020/11/09/sync-with-origin-repo-after-fork.html">git fork 后如何与原仓库同步</a></h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2020-11-09</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2020-12-14</span></span></div></header><div class="post-body"><div class="post-excerpt"><p>有时候我们需要 fork 别人的仓库，对代码进行修改，但是在原仓库进行更新时又不想重新 fork，那样会覆盖掉自己已有的修改，这时候我们就需要对原仓库的更新进行 merge，本文将从 fork 开始讲解如何进行操作</p>

        <h3 id="fork-仓库"   >
          <a href="#fork-仓库" class="heading-link"><i class="fas fa-link"></i></a>fork 仓库</h3>
      <p>这里以 <span class="exturl"><a class="exturl__link"   target="_blank" rel="noopener" href="https://github.com/catch6/hexo-client.git" >https://github.com/catch6/hexo-client.git</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span> 这个仓库为例，在 github 中点击 fork 按钮对别人的仓库进行 fork</p>
<p>执行 <code>git clone https://github.com/catch6/hexo-client.git</code> 命令克隆到本地</p>
<p>执行 <code>git remote -v</code> 命令查看远程仓库路径，输出如下：</p>
<figure class="highlight bash"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">origin	https://github.com/catch6/hexo-client.git (fetch)</span><br><span class="line">origin	https://github.com/catch6/hexo-client.git (push)</span><br></pre></td></tr></table></div></figure>

<p>如果只有上面 2 行，说明你未设置 upstream （中文叫：上游代码库）。一般情况下，设置好一次 upstream 后就无需重复设置。</p>
<p>执行命令 <code>git remote add upstream https://github.com/gaoyoubo/hexo-client.git</code> 添加上游，该命令没有任何输出</p>
<p>执行命令 <code>git remote -v</code> ，可以看到以下变化</p>
<figure class="highlight bash"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">origin	https://github.com/catch6/hexo-client.git (fetch)</span><br><span class="line">origin	https://github.com/catch6/hexo-client.git (push)</span><br><span class="line">upstream	https://github.com/gaoyoubo/hexo-client.git (fetch)</span><br><span class="line">upstream	https://github.com/gaoyoubo/hexo-client.git (push)</span><br></pre></td></tr></table></div></figure>

<p>执行命令 <code>git status</code> 检查本地是否有未提交的修改。如果有，则把你本地的有效修改，先从本地仓库推送到你的 github 仓库。最后再执行一次 <code>git status</code> 检查本地已无未提交的修改。</p>
<p>执行命令 <code>git fetch upstream</code> 抓取原仓库的更新</p>
<p>执行命令 <code>git checkout master</code> 切换到 master 分支</p>
<p>执行命令 <code>git merge upstream/master</code> 合并远程的 master 分支</p>
<p>执行命令 <code>git push</code> 把本地仓库向 github 仓库（你 fork 到自己名下的仓库）推送修改</p>
</div></div></article></section><nav class="paginator"><div class="paginator-inner"><span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="extend next" rel="next" href="/page/2/"><i class="fas fa-angle-right"></i></a></div></nav></div></div><div class="sidebar-wrap" id="sidebar-wrap"><aside class="sidebar" id="sidebar"><section class="sidebar-toc hide"></section><!-- ov = overview--><section class="sidebar-ov"><div class="sidebar-ov-author"><div class="sidebar-ov-author__avatar"><img class="sidebar-ov-author__avatar_img" src="https://cdn.qiniu.wenzuo.net/catch6.github.io/avatar.jpg" alt="avatar"></div><p class="sidebar-ov-author__text">觉得为时已晚的时候，恰恰是最早的时候。</p></div><div class="sidebar-ov-state"><a class="sidebar-ov-state-item sidebar-ov-state-item--posts" href="/archives/"><div class="sidebar-ov-state-item__count">12</div><div class="sidebar-ov-state-item__name">归档</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--categories" href="/categories/"><div class="sidebar-ov-state-item__count">2</div><div class="sidebar-ov-state-item__name">分类</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--tags" href="/tags/"><div class="sidebar-ov-state-item__count">10</div><div class="sidebar-ov-state-item__name">标签</div></a></div></section></aside></div><div class="clearfix"></div></div></main><footer class="footer" id="footer"><div class="footer-inner"><div><span>Copyright © 2015~2020</span><span class="footer__devider"></span><span>Catch</span></div><div class="busuanzi"><span class="busuanzi-siteuv"><span class="busuanzi-siteuv__icon"><i class="fas fa-user"></i></span><span class="busuanzi-siteuv__info">访问人数</span><span class="busuanzi-siteuv__value" id="busuanzi_value_site_uv"></span></span><span class="busuanzi-sitepv"><span class="busuanzi-siteuv__icon"><i class="fas fa-eye"></i></span><span class="busuanzi-siteuv__info">浏览总量</span><span class="busuanzi-siteuv__value" id="busuanzi_value_site_pv"></span></span></div></div></footer><div class="loading-bar" id="loading-bar"><div class="loading-bar__progress"></div></div><div class="back2top" id="back2top"><span class="back2top__icon"><i class="fas fa-rocket"></i></span></div></div><div class="search-mask"></div><div class="search-popup"><span class="search-close"></span><div class="search-input"><input placeholder="搜索文章（支持多关键词，请用空格分隔）"></div><div class="search-results"></div></div><script src="https://cdn.jsdelivr.net/npm/jquery@v3.4.1/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.ui.min.js"></script><script src="https://cdn.jsdelivr.net/npm/ribbon.js@latest/dist/ribbon.min.js" size="120" alpha="0.6" zIndex="-1"></script><script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script><script src="https://cdn.jsdelivr.net/npm/lazyload@2.0.0-rc.2/lazyload.min.js"></script><script>function initSearch() {
  var isXML = true;
  var search_path = 'search.json';

  if (!search_path) {
    search_path = 'search.xml';
  } else if (/json$/i.test(search_path)) {
    isXML = false;
  }

  var path = '/' + search_path;
  $.ajax({
    url: path,
    dataType: isXML ? 'xml' : 'json',
    async: true,
    success: function (res) {
      var datas = isXML ? $('entry', res).map(function () {
        // 将 XML 转为 JSON
        return {
          title: $('title', this).text(),
          content: $('content', this).text(),
          url: $('url', this).text()
        };
      }).get() : res;
      var $input = $('.search-input input');
      var $result = $('.search-results');
      // 搜索对象（标题、内容）的权重，影响显示顺序
      var WEIGHT = { title: 100, content: 1 };
      var searchPost = function () {
        var searchText = $input.val().toLowerCase().trim();
        // 根据空白字符分隔关键字
        var keywords = searchText.split(/[\s]+/);
        // 搜索结果
        var matchPosts = [];

        // 有多个关键字时，将原文字整个保存下来
        if (keywords.length > 1) {
          keywords.push(searchText);
        }
        // 防止未输入字符时搜索
        if (searchText.length > 0) {
          datas.forEach(function (data) {
            var isMatch  = false;
            // 没有标题的文章使用预设的 i18n 变量代替
            var title = (data.title && data.title.trim()) || '[ 文章无标题 ]';
            var titleLower = title && title.toLowerCase();
            // 删除 HTML 标签 和 所有空白字符
            var content = data.content && data.content.replace(/<[^>]+>/g, '');
            var contentLower = content && content.toLowerCase();
            // 删除重复的 /
            var postURL = data.url && decodeURI(data.url).replace(/\/{2,}/g, '/');
            // 标题中匹配到的关键词
            var titleHitSlice = [];
            // 内容中匹配到的关键词
            var contentHitSlice = [];

            keywords.forEach(function (keyword) {
              /**
              * 获取匹配的关键词的索引
              * @param {String} keyword 要匹配的关键字
              * @param {String} text 原文字
              * @param {Boolean} caseSensitive 是否区分大小写
              * @param {Number} weight 匹配对象的权重。权重大的优先显示
              * @return {Array}
              */
              function getIndexByword (word, text, caseSensitive, weight) {
                if (!word || !text) {
                  return [];
                };

                var startIndex = 0; // 每次匹配的开始索引
                var index = -1;     // 匹配到的索引值
                var result = [];    // 匹配结果

                if (!caseSensitive) {
                  word = word.toLowerCase();
                  text = text.toLowerCase();
                }

                while((index = text.indexOf(word, startIndex)) !== -1) {
                  var hasMatch = false;
                  // 索引位置相同的关键词，保留长度较长的
                  titleHitSlice.forEach(function (hit) {
                    if (hit.index === index && hit.word.length < word.length) {
                      hit.word = word;
                      hasMatch = true;
                    }
                  });
                  startIndex = index + word.length;
                  !hasMatch && result.push({ index: index, word: word, weight: weight });
                }
                return result;
              }
              titleHitSlice = titleHitSlice.concat(getIndexByword(keyword, titleLower, false, WEIGHT.title));
              contentHitSlice = contentHitSlice.concat(getIndexByword(keyword, contentLower, false, WEIGHT.content));
            });

            var hitTitle = titleHitSlice.length;
            var hitContent = contentHitSlice.length;

            if (hitTitle > 0 || hitContent > 0) {
              isMatch = true;
            }
            if (isMatch) {
              ;[titleHitSlice, contentHitSlice].forEach(function (hit) {
                // 按照匹配文字的索引的递增顺序排序
                hit.sort(function (left, right) {
                  return left.index - right.index;
                });
              });
              /**
              * 给文本中匹配到的关键词添加标记，从而进行高亮显示
              * @param {String} text 原文本
              * @param {Array} hitSlice 匹配项的索引信息
              * @param {Number} start 开始索引
              * @param {Number} end 结束索引
              * @return {String}
              */
              function highlightKeyword (text, hitSlice, start, end) {
                if (!text || !hitSlice || !hitSlice.length) {
                  return;
                }

                var result = '';
                var startIndex = start;
                var endIndex = end;
                hitSlice.forEach(function (hit) {
                  if (hit.index < startIndex) {
                    return;
                  }

                  var hitWordEnd = hit.index + hit.word.length;
                  result += text.slice(startIndex, hit.index);
                  result += '<b>' + text.slice(hit.index, hitWordEnd) + '</b>';
                  startIndex = hitWordEnd;
                });
                result += text.slice(startIndex, endIndex);
                return result;
              }

              var postData = {};
              // 文章总的搜索权重
              var postWeight = titleHitSlice.length * WEIGHT.title + contentHitSlice.length * WEIGHT.content;
              // 标记匹配关键词后的标题
              var postTitle = highlightKeyword(title, titleHitSlice, 0, title.length) || title;
              // 标记匹配关键词后的内容
              var postContent;
              // 显示内容的长度
              var SHOW_WORD_LENGTH = 200;
              // 命中关键词前的字符显示长度
              var SHOW_WORD_FRONT_LENGTH = 20;
              var SHOW_WORD_END_LENGTH = SHOW_WORD_LENGTH - SHOW_WORD_FRONT_LENGTH;

              // 截取匹配的第一个字符，前后共 200 个字符来显示
              if (contentHitSlice.length > 0) {
                var firstIndex = contentHitSlice[0].index;
                var start = firstIndex > SHOW_WORD_FRONT_LENGTH ? firstIndex - SHOW_WORD_FRONT_LENGTH : 0;
                var end = firstIndex + SHOW_WORD_END_LENGTH;
                postContent = highlightKeyword(content, contentHitSlice, start, end);
              } else { // 未匹配到内容，直接截取前 200 个字符来显示
                postContent = content.slice(0, SHOW_WORD_LENGTH);
              }
              postData.title = postTitle;
              postData.content = postContent;
              postData.url = postURL;
              postData.weight = postWeight;
              matchPosts.push(postData);
            }
          });
        }

        var resultInnerHtml = '';
        if (matchPosts.length) {
          // 按权重递增的顺序排序，使权重大的优先显示
          matchPosts.sort(function (left, right) {
            return right.weight - left.weight;
          });
          resultInnerHtml += '<ul>';
          matchPosts.forEach(function (post) {
            resultInnerHtml += '<li><a class="search-results-title" href="' + post.url + '">';
            resultInnerHtml += post.title;
            resultInnerHtml += '</a><div class="search-results-content">';
            resultInnerHtml += post.content;
            resultInnerHtml += '</div></li>';
          });
          resultInnerHtml += '</ul>';
        } else {
          resultInnerHtml += '<div class="search-results-none"><i class="far fa-meh"></i></div>';
        }
        $result.html(resultInnerHtml);
      };
      $input.on('input', searchPost);
      $input.on('keyup', function (e) {
        if (e.keyCode === Stun.utils.codeToKeyCode('Enter')) {
          searchPost();
        }
      });
    }
  });
}

function closeSearch () {
  $('body').css({ overflow: 'auto' });
  $('.search-popup').css({ display: 'none' });
  $('.search-mask').css({ display: 'none' });
}

window.addEventListener('DOMContentLoaded', function () {
  Stun.utils.pjaxReloadLocalSearch = function () {
    $('.header-nav-search').on('click', function (e) {
      e.stopPropagation();
      $('body').css('overflow', 'hidden');
      $('.search-popup')
        .velocity('stop')
        .velocity('transition.expandIn', {
          duration: 300,
          complete: function () {
            $('.search-popup input').focus();
          }
        });
      $('.search-mask')
        .velocity('stop')
        .velocity('transition.fadeIn', {
          duration: 300
        });

      initSearch();
    });
    $('.search-mask, .search-close').on('click', function () {
      closeSearch();
    });
    $(document).on('keydown', function (e) {
      // Escape <=> 27
      if (e.keyCode === Stun.utils.codeToKeyCode('Escape')) {
        closeSearch();
      }
    });
  };

  Stun.utils.pjaxReloadLocalSearch();
}, false);

function safeOpenUrl(url) {
  var newTab = window.open();
  newTab.opener = null;
  newTab.location = url;
}

function extSearch(engine) {
  var engines = {
    google: 'https://www.google.com/search?q=',
    bing: 'https://cn.bing.com/search?q=',
    baidu: 'https://www.baidu.com/s?ie=UTF-8&wd=',
  };
  var host = window.location.host;
  var query = $('.search-input input').val().toLowerCase().trim();
  var uri = engines[engine] + query + ' site:' + host;

  if (query) {
    safeOpenUrl(uri);
  } else {
    Stun.utils.popAlert('warning', '请输入字符');
  }
}

var assistSearchList = window.CONFIG.assistSearch;

if (Array.isArray(assistSearchList)) {
  assistSearchList.forEach(function (name) {
    document.querySelector('.search-btns-item--' + name).addEventListener('click', function () {
      extSearch(name);
    }, false);
  });
}</script><script src="https://cdn.jsdelivr.net/npm/quicklink@1.0.1/dist/quicklink.umd.js"></script><script>function initQuicklink() {
  quicklink({
    timeout: '10000',
    priority: true,
    ignores: [uri => uri.includes('#'), uri => uri === 'https://catch6.github.io/', /\/api\/?/,uri => uri.includes('.xml'),uri => uri.includes('.zip'),(uri, el) => el.hasAttribute('nofollow'),(uri, el) => el.hasAttribute('noprefetch')]
  });
}

if (false || false) {
  initQuicklink();
} else {
  window.addEventListener('DOMContentLoaded', initQuicklink, false);
}</script><script src="https://cdn.jsdelivr.net/gh/sukkaw/busuanzi@latest/bsz.pure.mini.js" async></script><script src="/js/utils.js?v=2.3.0"></script><script src="/js/stun-boot.js?v=2.3.0"></script><script src="/js/scroll.js?v=2.3.0"></script><script src="/js/header.js?v=2.3.0"></script><script src="/js/sidebar.js?v=2.3.0"></script><script type="application/json" src="/search.json"></script></body></html>